////////////////////////////////////////////////////////////
//
// association.c
// PE23 20021023 update algorithm
// These functions will handle all the association-related messages. This
// includes, association, reassociation and disassociation.
//
///////////////////////////////////////////////////////////////

#include "os_common.h"

//===========================================================================
//  SendAssociationRequest --
//
//  Description:
//    Send the association request frame or reassociation request to the AP.
//
//  Arguments:
//    Adapter       - The pointer to the Miniport Adapter Context
//    peerSTAAddress- The Address of the peer STA (acting as an AP) that is
//                    desired to associate with.
//    capabilityInfo- Capability information in the Asso. request. To report
//                    this STA capability.
//    ListenInterval- The number of beacon intervals that may pass before this
//                    STA awakens and listerns for the next beacon.
//
//  Return Value:
//   -1     - Failed to send.
//    1     - Has sent to the Tx handler
//============================================================================
CHAR SendAssociationRequest(PWB32_ADAPTER   Adapter,
                            USHORT          iMSindex,
                            BOOL 			Reasso)
{
	USHORT 	iFildOffset = 0;
	UCHAR	*msg;
	struct  Management_Frame* msgHeader;
    struct  Association_Request_Frame_Body* msgBody;

    // Get the free data buffer
	if ((msg = MLMEGetMMPDUBuffer(Adapter)) == NULL)
	{	// No available data buffer now. Stop sending the MMPDU.
		Adapter->sMlmeFrame.wNumTxMMPDUDiscarded++;
		return -1;
	}
	msgHeader = (struct Management_Frame*) &msg[0];
	msgBody   = (struct Association_Request_Frame_Body*)&msg[sizeof(struct Management_Frame)];

	if (Reasso)
		msgHeader->frame_control.mac_frame_info = MAC_SUBTYPE_MNGMNT_REASSOC_REQUEST;
	else
		msgHeader->frame_control.mac_frame_info = MAC_SUBTYPE_MNGMNT_ASSOC_REQUEST;
	msgHeader->frame_control.to_ds          = 0;    // ToDS = 0 for MMPDU
	msgHeader->frame_control.from_ds        = 0;    // FromDS = 0 for MMPDU
	msgHeader->frame_control.more_frag      = 0;
	msgHeader->frame_control.retry          = 0;
	msgHeader->frame_control.more_data      = 0;
	msgHeader->frame_control.order          = 0;
	msgHeader->frame_control.pwr_mgt        = 0;
	msgHeader->frame_control.WEP            = 0;
	msgHeader->duration                     = 0;    // Set by the MDS
	
	#ifdef _PE_TX_DUMP_
	//WBDEBUG(("addr of DA =%p\n", 		msgHeader->DA));
	//WBDEBUG(("addr of SA =%p\n", 		msgHeader->SA));
	//WBDEBUG(("addr of BSSID =%p\n",		msgHeader->BSSID));
	#endif
	OS_MEMORY_COPY( msgHeader->DA, psBSS(iMSindex)->abPeerAddress, MAC_ADDR_LENGTH );
	OS_MEMORY_COPY( msgHeader->SA, psLOCAL->ThisMacAddress, MAC_ADDR_LENGTH );
	OS_MEMORY_COPY( msgHeader->BSSID, psBSS(iMSindex)->abBssID, MAC_ADDR_LENGTH );

    // HW-MAC automatically generates the frame sequence number
    // MDS automatically generates the fragment number.

	// now set the associtaion request information
        //20060926 add by anson's endian
	msgBody->capability_information = cpu_to_le16( psSME->wCapabilityInfo );
	msgBody->listenInterval = cpu_to_le16( psLOCAL->ListenInterval );
	if(Reasso)
	{
		OS_MEMORY_COPY( msgBody->Current_AP_Address, psBSS(psLOCAL->wOldSTAindex)->abPeerAddress, MAC_ADDR_LENGTH );
		iFildOffset = sizeof(struct Management_Frame) + sizeof(struct Association_Request_Frame_Body);
	}
	else
	{
		iFildOffset = sizeof(struct Management_Frame) + sizeof(struct Association_Request_Frame_Body)-(sizeof(UCHAR)*6);
		//the space of the Current_AP_Address is skiped,beacuse association request frame don't have this field
	}

	// now set the SSID and supported rates element lists
	OS_MEMORY_COPY( &msg[iFildOffset], &psBSS(iMSindex)->SSID, psBSS(iMSindex)->SSID.Length + 2 );
	iFildOffset += (psBSS(iMSindex)->SSID.Length + 2);

	//set the (extended)supported rates element
	DesiredRate2InfoElement(
		                    Adapter, msg, &iFildOffset,
							psSME->BSSBasicRateSet, psSME->NumOfBSSBasicRate,
							psSME->OperationalRateSet, psSME->NumOfOperationalRate
						   );
	//WPA
	psSME->boReassoc = Reasso;
	if ((psSME->bDesiredAuthMode==WPA_AUTH)||(psSME->bDesiredAuthMode==WPAPSK_AUTH))
	{
		CreateWpaIE(Adapter,&iFildOffset,msg, msgHeader, msgBody,iMSindex);//Added ws by 05/15/04
	}
    #ifdef _WPA2_
	else if((psSME->bDesiredAuthMode==WPA2_AUTH) || (psSME->bDesiredAuthMode==WPA2PSK_AUTH))
	{
		//WPA2
		CreateRsnIE(Adapter,&iFildOffset,msg, msgHeader, msgBody,iMSindex);//Added ws by 05/15/04
	}
    #endif //end def _WPA2_

	//
	// 20061108 Add WPS_IE
	//
	if( psLOCAL->IE_Append_size )
	{
		PUCHAR	WPSBuf = msg + iFildOffset;
		UCHAR	WPS_IE[16]={ 0xdd, 0x0e,					// WSC_ID_VERSION 0x104A  <-- It's Big endian
							 0x00, 0x50, 0xf2, 0x04,		// WPS_OUI 00 50 F2 04  <-- It's big endian
							 0x10, 0x4A, 0x00, 0x01, 0x10,	// WSC_ID_VERSION  0x104A  <-- It's Big endian
							 0x10, 0x3A, 0x00, 0x01, 0x01 }; // WSC_ID_REQ_TYPE 0x103A  <-- It's Big endian
		OS_MEMORY_COPY( WPSBuf, WPS_IE, 16 );
		iFildOffset += 16;
	}

	// now, iFildOffset is the frame length
	if (1 == MLMESendFrame(Adapter,(UCHAR *)&msg[0],iFildOffset,FRAME_TYPE_802_11_MANAGEMENT))
		return 1;
    	else
	{
		//return MLME buffer
		MLMEfreeMMPDUBuffer(Adapter, msg);
        	return -1;
	}
}

//===========================================================================
//  SendDisassociation -- for DUT test only
//  Implement like SendDeauthentication()
//============================================================================
CHAR SendDisassociation(PWB32_ADAPTER   Adapter,
                        USHORT 			iMSindex,
                        USHORT        	reasonCode)
{
	PUCHAR	msg;
	struct Management_Frame* msgHeader;
	struct Deauthentication_Frame_Body* msgBody;

	if ((msg=MLMEGetMMPDUBuffer(Adapter))==NULL)
	{
		Adapter->sMlmeFrame.wNumTxMMPDUDiscarded++;
		return -1;  // fail get free msg buffer
	}
	msgHeader = (struct Management_Frame *) &msg[0];

	// setup Frame-Header subfields
	msgHeader->frame_control.mac_frame_info = MAC_SUBTYPE_MNGMNT_DISASSOCIATION;
    msgHeader->frame_control.to_ds      = 0;    // =0 for MMPDU
    msgHeader->frame_control.from_ds    = 0;    // =0 for MMPDU
	msgHeader->frame_control.more_frag 	= 0;
    msgHeader->frame_control.retry      = 0;
	msgHeader->frame_control.more_data 	= 0;
    msgHeader->frame_control.order      = 0;
    msgHeader->frame_control.pwr_mgt    = 0;
    msgHeader->frame_control.WEP        = 0;    // PD43 20021127 Modified
    msgHeader->duration                 = 0;    // Set by the MDS
	
    OS_MEMORY_COPY( msgHeader->DA, Adapter->asBSSDescriptElement[iMSindex].abPeerAddress, MAC_ADDR_LENGTH );
	OS_MEMORY_COPY( msgHeader->SA, Adapter->sLocalPara.ThisMacAddress, MAC_ADDR_LENGTH );
	OS_MEMORY_COPY( msgHeader->BSSID, psBSS(Adapter->sLocalPara.wConnectedSTAindex)->abBssID, MAC_ADDR_LENGTH );
	// FrameSequenceNumber is generated by HW-MAC

	msgBody = (struct Deauthentication_Frame_Body*) &msg[sizeof(struct Management_Frame)];
	msgBody->reasonCode = cpu_to_le16( reasonCode ); //20060926 add by anson's endian

	// now send this message out
	if (1 == MLMESendFrame( Adapter,
					(UCHAR *) &msg[0],
					sizeof(struct Management_Frame) + sizeof(struct Disassociation_Frame_Body),
					FRAME_TYPE_802_11_MANAGEMENT))
        return 1;
    else
	{
		//return MLME buffer
		MLMEfreeMMPDUBuffer(Adapter, msg);
        return -1;
	}
}

